package com.stox.services.data.provider.repository.file;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.stox.services.core.repository.AbstractPartitioningFileRepository;
import com.stox.services.data.provider.manager.ScripManager;
import com.stox.services.data.provider.repository.BarRepository;
import com.stox.services.data.provider.repository.file.iterator.OffsetAndCountAwareBarIterator;
import com.stox.services.data.provider.repository.file.iterator.StartAndCountAwareBarIterator;
import com.stox.services.data.provider.repository.file.iterator.StartAndEndAwareBarIterator;
import com.stox.shared.model.Bar;
import com.stox.shared.model.Scrip;
import com.stox.shared.model.enumeration.BarSpan;

@Component
public class BarFileRepository extends AbstractPartitioningFileRepository<Bar, Scrip> implements BarRepository {
	
	@Autowired
	private ScripManager scripManager;
	
	@Override
	protected String getFilePath(Scrip scrip) {
		return getFilebasePath()+File.separator+
				scrip.getExchangeId()+File.separator+scrip.getId()+".csv";
	}
	
	@Override
	protected synchronized Bar deserialize(String text, Scrip scrip) {
		try{
			return new Bar(scrip.getId(), text);
		}catch(RuntimeException e){
			throw e;
		}
	}
	
	@Override
	public synchronized List<Bar> findByScripId(Long scripId, BarSpan barSpan, Date start,int count) {
		StartAndCountAwareBarIterator iterator = new StartAndCountAwareBarIterator(start, count);
		iterator.setSpanType(barSpan);
		iterate(iterator, scripManager.findOne(scripId));
		return iterator.getBars();
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId, BarSpan barSpan, Date start, Date end) {
		StartAndEndAwareBarIterator iterator = new StartAndEndAwareBarIterator(start, end);
		iterator.setSpanType(barSpan);
		iterate(iterator, scripManager.findOne(scripId));
		return iterator.getBars();
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId, BarSpan barSpan, Integer offset, Integer count){
		OffsetAndCountAwareBarIterator iterator = new OffsetAndCountAwareBarIterator(offset,count);
		iterator.setSpanType(barSpan);
		iterate(iterator, scripManager.findOne(scripId));
		return iterator.getBars();
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar entity) {
				bars.add(entity);
				return true;
			}
		}, scripManager.findOne(scripId));
		return bars;
	}

	@Override
	public List<Bar> findByScripId(Long scripId, final Date start){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar bar) {
				bars.add(bar);
				return (bar.getDate().after(start) || bar.getDate().equals(start));
			}
		}, scripManager.findOne(scripId));
		return bars;
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId,final int count){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			private int subCount;
			public boolean shouldContinue(Bar bar) {
				bars.add(bar);
				return subCount <= count;
			}
		}, scripManager.findOne(scripId));
		return bars;
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId, final Date start, final Date end) {
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar bar) {
				if((bar.getDate().equals(start) || bar.getDate().after(start)) &&
						(bar.getDate().equals(end) || bar.getDate().before(end))){
					bars.add(bar);
				}
				return bar.getDate().before(start);
			}
		}, scripManager.findOne(scripId));
		return bars;
	}
	
	public Bar save(Bar bar) {
		return super.save(bar, bar.getScrip());
	}

	@Override
	protected String serialize(Bar bar) {
		return bar.toString();
	}

}
